home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 1999 February
/
Macworld (1999-02).dmg
/
Cinema 4D GO demo
/
Gumption Plug-ins
/
Plug-ins
/
Freeware
/
Fillet
/
FILLET.COF
Wrap
Text File
|
1998-03-29
|
12KB
|
451 lines
/*
The fillet plugin generates a set of splines which form a blend between two
polygon objects. After (manually) setting the direction and starting points
of each spline, create a Skin object from the group.
Bonus plugins:
Inflate object - compute average normal at each vertex
and move outward a specified distance
Derive spline of intersection - draw a spline along the surface of the
selected object, where it is intersected by the specified cutting object
Send comments, praise, money :-) etc. to:
Jim Hasselbrook
hassel@bellatlantic.net
This software is provided free, AS IS. Feel free to modify it to suit your needs.
*/
copy(doc, obj, newname)
{
StatusSetText("Copying object", TRUE);
var i;
var pcount = obj->GetPointCount();
var ecount = obj->GetEdgeCount();
var tcount = obj->GetTriangleCount();
var qcount = obj->GetQuadrangleCount();
var newobj = doc->NewPolygonObject(newname, NULL, NULL, pcount, ecount, tcount, qcount);
var t = new(Triangle);
var q = new(Quadrangle);
var e = new(Edge);
var mat = new(Matrix);
obj->GetMg(mat); // obj to world coords
for (i=0; i<pcount; i++) {
StatusSetBar(i*100.0/pcount, TRUE);
newobj->SetPoint(i, mat->MulP(obj->GetPoint(i)));
}
for (i=0; i<ecount; i++) {
StatusSetBar(i*100.0/ecount, TRUE);
obj->GetEdge(i, e);
newobj->SetEdge(i, e);
}
for (i=0; i<tcount; i++) {
StatusSetBar(i*100.0/tcount, TRUE);
obj->GetTriangle(i, t);
newobj->SetTriangle(i, t);
}
for (i=0; i<qcount; i++) {
StatusSetBar(i*100.0/qcount, TRUE);
obj->GetQuadrangle(i, q);
newobj->SetQuadrangle(i, q);
}
newobj->UpdateObject();
return newobj;
}
doInflate(doc, obj, amount)
{
var pcount = obj->GetPointCount();
var tcount = obj->GetTriangleCount();
var qcount = obj->GetQuadrangleCount();
StatusSetText("Copying object", TRUE);
var newobj = copy(doc, obj, stradd(stradd(obj->GetName(), "+"), tostring(amount)));
if (amount != 0.0)
{
var i;
var norms = new(array, pcount);
var t = new(Triangle);
var q = new(Quadrangle);
var a, b, c, d, norm;
StatusSetText("Calculating normals", TRUE);
for (i=0; i<pcount; i++)
{
StatusSetBar(i*100.0/pcount, TRUE);
norms[i] = vector(0.0, 0.0, 0.0);
}
for (i=0; i<tcount; i++)
{
StatusSetBar(i*100.0/tcount, TRUE);
newobj->GetTriangle(i, t);
a = newobj->GetPoint(t->a);
b = newobj->GetPoint(t->b);
c = newobj->GetPoint(t->c);
norm = vnorm(vcross(a-b, a-c));
norms[t->a] += norm;
norms[t->b] += norm;
norms[t->c] += norm;
}
for (i=0; i<qcount; i++)
{
StatusSetBar(i*100.0/qcount, TRUE);
newobj->GetQuadrangle(i, q);
a = newobj->GetPoint(q->a);
b = newobj->GetPoint(q->b);
c = newobj->GetPoint(q->c);
d = newobj->GetPoint(q->d);
norm = vnorm(vcross(a-b, a-c) + vcross(a-c, a-d));
norms[q->a] += norm;
norms[q->b] += norm;
norms[q->c] += norm;
norms[q->d] += norm;
}
StatusSetText("Inflating points", TRUE);
for (i=0; i<pcount; i++)
{
StatusSetBar(i*100.0/pcount, TRUE);
newobj->SetPoint(i, newobj->GetPoint(i) + vnorm(norms[i]) * amount);
}
}
newobj->UpdateObject();
return newobj;
}
isInside(p,a,b,c)
{
var vab = vcross(a-p, b-p);
var vbc = vcross(b-p, c-p);
var vca = vcross(c-p, a-p);
// for accuracy, choose component with greatest magnitude
if (abs(vab.x) > abs(vab.y) && (abs(vab.x) > abs(vab.z))) // x
{
return (vab.x >= 0.0 && vbc.x >= 0.0 && vca.x >= 0.0) || (vab.x <= 0.0 && vbc.x <= 0.0 && vca.x <= 0.0);
}
else if (abs(vab.y) > abs(vab.z)) // y
{
return (vab.y >= 0.0 && vbc.y >= 0.0 && vca.y >= 0.0) || (vab.y <= 0.0 && vbc.y <= 0.0 && vca.y <= 0.0);
}
else // z
{
return (vab.z >= 0.0 && vbc.z >= 0.0 && vca.z >= 0.0) || (vab.z <= 0.0 && vbc.z <= 0.0 && vca.z <= 0.0);
}
}
edgeIntersectsTriangle(ea, eb, a, b, c)
{
var v = vnorm(vcross(a-b, a-c));
var w = eb - ea;
var wv = w * v; // dot product
if (wv) // if zero, edge is || to plane of triangle
{
var x = ((a - ea) * v) / wv;
if (0.0 <= x && x <= 1.0) // intersection with plane lies between e->a and e->b
{
var p = ea + x * w;
if (isInside(p, a, b, c)) // point lies inside triangle
{
return p;
}
}
}
return NULL;
}
/*
Spline point sorting, courtesy of John Detch, 3D Gear
*/
ClosePointSort(obj)
{
var sp1=new(SplinePoint),sp2=new(SplinePoint);
var num=obj->GetPointCount();
var i,j,last=new(SplinePoint);
var len,nlen,v=vector(0,0,0);
StatusSetText("Sorting spline points", TRUE);
for(i=0;i<num;i++){
obj->GetPoint(i,sp1);
len=100000000.0;
for(j=i+1;j<num;j++){
obj->GetPoint(j,sp2);
v=sp1->p-sp2->p;
nlen=vlen(v);
if(nlen<len){
last=j;
len=nlen;
}
}
if(j!=i+1){
obj->GetPoint(i+1,sp1);
obj->GetPoint(last,sp2);
obj->SetPoint(i+1,sp2);
obj->SetPoint(last,sp1);
}
}
}
/*
for each edge in objA
{
find edges of objA which intersect some polyB of objB, get point of intersection
}
*/
cut_A_with_B(doc, group, objA, objB)
{
var i, j;
var splineobj = doc->NewSplineObject("Spline",group,NULL,0);
var newPoint = new(SplinePoint);
var info = new(SplineInfo);
splineobj->GetSplineInfo(info);
info->closed = TRUE;
splineobj->SetSplineInfo(info);
var lowerA = vector(0.0, 0.0, 0.0);
var upperA = vector(0.0, 0.0, 0.0);
var lowerB = objB->GetBox1();
var upperB = objB->GetBox2();
var ecountA = objA->GetEdgeCount();
var tcountB = objB->GetTriangleCount();
var qcountB = objB->GetQuadrangleCount();
var e = new(Edge);
var t = new(Triangle);
var q = new(Quadrangle);
var a, b, c, d, ea, eb, p, lastPoint;
var ta = new(array, tcountB);
var tb = new(array, tcountB);
var tc = new(array, tcountB);
var qa = new(array, qcountB);
var qb = new(array, qcountB);
var qc = new(array, qcountB);
var qd = new(array, qcountB);
for (i=0; i<tcountB; i++)
{
objB->GetTriangle(i, t);
ta[i] = objB->GetPoint(t->a);
tb[i] = objB->GetPoint(t->b);
tc[i] = objB->GetPoint(t->c);
}
for (i=0; i<qcountB; i++)
{
objB->GetQuadrangle(i, q);
qa[i] = objB->GetPoint(q->a);
qb[i] = objB->GetPoint(q->b);
qc[i] = objB->GetPoint(q->c);
qd[i] = objB->GetPoint(q->d);
}
StatusSetText("Finding intersection", TRUE);
for (i=0; i<ecountA; i++)
{
StatusSetBar(i*100.0/ecountA, TRUE);
objA->GetEdge(i, e);
ea = objA->GetPoint(e->a);
eb = objA->GetPoint(e->b);
if ((ea.x < lowerB.x && eb.x < lowerB.x) || (ea.x > upperB.x && eb.x > upperB.x)) continue;
if ((ea.y < lowerB.y && eb.y < lowerB.y) || (ea.y > upperB.y && eb.y > upperB.y)) continue;
if ((ea.z < lowerB.z && eb.z < lowerB.z) || (ea.z > upperB.z && eb.z > upperB.z)) continue;
if (ea.x < eb.x) { lowerA.x = ea.x; upperA.x = eb.x; } else { lowerA.x = eb.x; upperA.x = ea.x; }
if (ea.y < eb.y) { lowerA.y = ea.y; upperA.y = eb.y; } else { lowerA.y = eb.y; upperA.y = ea.y; }
if (ea.z < eb.z) { lowerA.z = ea.z; upperA.z = eb.z; } else { lowerA.z = eb.z; upperA.z = ea.z; }
for (j=0; j<tcountB; j++)
{
a = ta[j]; b = tb[j]; c = tc[j];
if ((a.x < lowerA.x && b.x < lowerA.x && c.x < lowerA.x) ||
(a.x > upperA.x && b.x > upperA.x && c.x > upperA.x)) continue;
if ((a.y < lowerA.y && b.y < lowerA.y && c.y < lowerA.y) ||
(a.y > upperA.y && b.y > upperA.y && c.y > upperA.y)) continue;
if ((a.z < lowerA.z && b.z < lowerA.z && c.z < lowerA.z) ||
(a.z > upperA.z && b.z > upperA.z && c.z > upperA.z)) continue;
p = edgeIntersectsTriangle(ea, eb, a, b, c);
if (p && (!lastPoint || p != lastPoint))
{
newPoint->p = p;
splineobj->AddPoint(newPoint);
lastPoint = p;
}
}
for (j=0; j<qcountB; j++)
{
a = qa[j]; b = qb[j]; c = qc[j]; d = qd[j];
if ((a.x < lowerA.x && b.x < lowerA.x && c.x < lowerA.x && d.x < lowerA.x) ||
(a.x > upperA.x && b.x > upperA.x && c.x > upperA.x && d.x > upperA.x)) continue;
if ((a.y < lowerA.y && b.y < lowerA.y && c.y < lowerA.y && d.y < lowerA.y) ||
(a.y > upperA.y && b.y > upperA.y && c.y > upperA.y && d.y > upperA.y)) continue;
if ((a.z < lowerA.z && b.z < lowerA.z && c.z < lowerA.z && d.z < lowerA.z) ||
(a.z > upperA.z && b.z > upperA.z && c.z > upperA.z && d.z > upperA.z)) continue;
p = edgeIntersectsTriangle(ea, eb, a, b, c);
if (p && (!lastPoint || p != lastPoint))
{
newPoint->p = p;
splineobj->AddPoint(newPoint);
lastPoint = p;
}
p = edgeIntersectsTriangle(ea, eb, c, d, a);
if (p && (!lastPoint || p != lastPoint))
{
newPoint->p = p;
splineobj->AddPoint(newPoint);
lastPoint = p;
}
}
}
ClosePointSort(splineobj);
splineobj->UpdateObject();
}
inflate(doc)
{
var obj = doc->FindFirstActiveObject();
if(!obj || !instanceof(obj,PolygonObject))
{
TextDialog("Must select a polygon object!", DLG_OK);
return;
}
var d = new (SimpleDialog);
d->SetData(0,"Amount",FIELD_FLOAT,-1000000.0,1000000.0,10.0);
d->SetTitle("Inflate by Amount");
if (!d->DoDialog()) return FALSE;
var amount = d->GetData(0);
doInflate(doc, obj, amount);
doc->SendMessage(DOCUMENT_CHANGED);
StatusClear();
}
intersect(doc)
{
var objA = doc->FindFirstActiveObject();
if(!objA || !instanceof(objA, PolygonObject))
{
TextDialog("Must select a polygon object!", DLG_OK);
return;
}
var d = new (SimpleDialog);
d->SetData(0,"Cutting Object",FIELD_STRING,0.0,0.0,"");
d->SetTitle("Derive Spline of Intersection");
if (!d->DoDialog()) return FALSE;
var objB = doc->FindObject(d->GetData(0));
if(!objB || !instanceof(objB, PolygonObject))
{
TextDialog("Must select a polygon object to cut with!", DLG_OK);
return;
}
var copyA = copy(doc, objA, "tempA");
var copyB = copy(doc, objB, "tempB");
cut_A_with_B(doc, NULL, copyA, copyB);
doc->KillObject(copyA);
doc->KillObject(copyB);
doc->SendMessage(DOCUMENT_CHANGED);
StatusClear();
}
fillet(doc)
{
var d = new (SimpleDialog);
d->SetData(0,"Object A",FIELD_STRING,0.0,0.0,"");
d->SetData(1,"Object B",FIELD_STRING,0.0,0.0,"");
d->SetData(2,"Fillet Radius",FIELD_FLOAT,-1000000.0,1000000.0,20.0);
d->SetData(3,"Number of Steps",FIELD_INTEGER,1,20,1);
d->SetTitle("Derive Fillet Splines");
if (!d->DoDialog()) return FALSE;
var objA = doc->FindObject(d->GetData(0));
var objB = doc->FindObject(d->GetData(1));
var radius = d->GetData(2);
var steps = d->GetData(3);
if(!objA || !objB || !instanceof(objA, PolygonObject) || !instanceof(objB, PolygonObject))
{
TextDialog("Must select two polygon objects!", DLG_OK);
return;
}
var group = doc->NewPolygonObject("Fillet Group",NULL,NULL,0,0,0,0);
var i;
for (i=0; i<=steps; i++)
{
var angle = (PI / 2.0) * float(i) / float(steps);
var copyA = doInflate(doc, objA, (1 - cos(angle)) * radius);
var copyB = doInflate(doc, objB, (1 - sin(angle)) * radius);
if (i < (steps+1)/2)
{
cut_A_with_B(doc, group, copyA, copyB);
}
else
{
cut_A_with_B(doc, group, copyB, copyA);
}
doc->KillObject(copyA);
doc->KillObject(copyB);
}
group->UpdateObject();
doc->SendMessage(DOCUMENT_CHANGED);
StatusClear();
}
main()
{
RegisterMenuHook("Spline of Intersection","intersect");
RegisterMenuHook("Inflate","inflate");
RegisterMenuHook("Fillet","fillet");
}